package com.titaniume.java1;

import com.titaniume.java.Person;
import org.junit.Test;

import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;

/**
 *@program: JavaSenior
 *@description:
 *
 *   |-----Collection 接口 ： 单列集合 用于存储一个一个对象
 *     |-----Set接口:存储 无序的、不可重复数据   -------> 高中讲的集合
 *        |-----HashSet：作Set接口的主要实现类；线程不安全的，可以存储null值
 *              |-----LinkedHashSet：作为HashSet的子类，遍历内部数据时可以安装添加的顺序进行遍历
 *              对于频繁的遍历操作 LinkedHashSet 高于HashSet
 *       |-----TreeSet: 可以按添加对象的指定属性 ，进行排序.
 *
 *
 * 1.Set接口中没有额外定义的新方法。使用的是Collectino定义的方法
 * 2.要求 ：向Set中添加的数据，其所在的类一定要重写hashCode()和equals()方法
 *  要求：重写的hashCode()和equals()尽可能保持一致性；相等的对象必须具有相等的散列码
 *
 *
 *@author: renfei.huang
 *@create: 2021-10-11 16:59
 */
public class SetTest {


    /*
    *
    *
    * 一、Set: 存储无序的 、不可重复的数据
    *
    * 1.无序性：不等于随机性 。存储的数据在底层数组中并非按照数组索引顺序添加。
    * 而是根据数据的哈希值决定的
    *
    * 2.不可重复性：保证添加的元素按照equals() 判断时，不能返回true
    * 即 相同的元素只能有一个。
    *
    *
    *二: 添加元素的过程，以HashSet为例
    *   我们向HashSet中添加元素a,首先调用元素a的hashCode()方法，计算元素a的哈希值，
    *   此哈希值接着通过某种算法计算出HashSet底层数组中存放位置（即为：索引位置），判断数组位置上否已有元素：
    *      如果此位置上没有其他元素,则元素a添加成功    ---情况一
    *      如果此位置上有其他元素b（或已链表存在的多个元素），首先比较元素a与元素b的hash值
    *         如果hash值不相同，则元素a添加成功  ---情况二
    *         如果has值相同，进而需要调用元素a所在类的equals()方法：
    *           equals()返回true,元素a添加失败
    *           equals()返回false,元素a添加成功  ---情况三
    *
    *
    *      对于添加成功的情况二和情况三而言，元素a与已经存在的指定索引位置上数据以链表方式存储
    *       jdk7: 元素a放到数组中，指向原来的元素
    *       jdk8:原来的元素在数组中，指向元素a
    *      总结：七上八下
    *
    *       HashSet底层： 数组+链表结构
    *
    *二、添加元素的过程、已HashSet为例：
    *
    *
    *
    * */

    @Test
    public  void test(){


        //重写了hashCode() new User("xx",12) 变成了重复
        Set set = new HashSet();
        set.add(456);
        set.add(123);
        set.add("AAS");
        set.add("CC");
        set.add(new User("xx",12));
        set.add(new User("xx",12));
        set.add(13);
        Iterator iterator = set.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }



    /*
    *
    * LinkedHashSet的使用
    * LinkedHashSet 作为HashSet的子类，在添加数据的同时，每个数据海维护了两个引用，记录此数据的
    * 前一个和后一个操作
    *
    * 优点： 对于频繁的遍历操作 LinkedHashSet 高于HashSet
    *
    *
    * */
    @Test
    public  void test2(){

        Set set = new LinkedHashSet();
        set.add(456);
        set.add(123);
        set.add("AAS");
        set.add("CC");
        set.add(new User("xx",12));
        set.add(new User("xx",12));
        set.add(13);
        Iterator iterator = set.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }
}
